package com.woniu.config;

import com.woniu.realm.CustomRealm;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.codec.Base64;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.CookieRememberMeManager;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.LinkedHashMap;
import java.util.Map;

/**
 * @author Kevin Kwok
 * @create 2021-04-13 10:56
 */
@Configuration
public class ShiroConfig {
    @Bean
    public Realm realm() {
        CustomRealm customRealm = new CustomRealm();
        HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
        matcher.setHashIterations(1024);
        matcher.setHashAlgorithmName("md5");
        customRealm.setCredentialsMatcher(matcher);
        return customRealm;
    }

    @Bean
    public DefaultWebSecurityManager defaultWebSecurityManager() {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        // 设置自定义 realm.
        securityManager.setRealm(realm());
        securityManager.setRememberMeManager(cookieRememberMeManager());
        return securityManager;
    }


    /**
     * 先走 filter ，然后 filter 如果检测到请求头存在 token，则用 token 去 login，走 Realm 去验证
     */
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean() {
        //实例化filter工厂
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        //注册manager
        shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager());
        /*
        * LinkedMap是有序的，shiro会根据添加的顺序进行拦截，匹配到过滤器以后不再继续向下查找过滤器
        * anon：所有的url都可以在不登录的情况下访问
        * authc：所有的url都必须在认证通过的情况下才可以访问
        * */
        Map<String, String> map = new LinkedHashMap<>();
        map.put("/user/login","anon");
        map.put("/favicon.ico","anon");
        //map.put("/user/logout","anon");//这个注销的方式在前后端分离之后失效，注意！！！
        map.put("/**","user");


        //未登录的时候重定向的网页请求
        shiroFilterFactoryBean.setLoginUrl("/user/unlogin");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
        return shiroFilterFactoryBean;
    }
    /*
    * 配置控制层的前置通知
    * 在通知中判断权限是否足够
    * */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor() {
        AuthorizationAttributeSourceAdvisor advisor=new AuthorizationAttributeSourceAdvisor();
        advisor.setSecurityManager(defaultWebSecurityManager());
        return advisor;
    }

    /*
    * 强制去设置为cglib代理
    * */
    @Bean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator(){
        DefaultAdvisorAutoProxyCreator app=new DefaultAdvisorAutoProxyCreator();
        app.setProxyTargetClass(true);
        return app;
    }

    /*
    * 配置rememberMe
    * */
    @Bean
    public CookieRememberMeManager cookieRememberMeManager() {
        //实例化rememberme管理器
        CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
        //定义Cookie cookie的名字为rememberMe
        SimpleCookie cookie = new SimpleCookie("rememberMe");
        //定义Cookie的有效时间(s)
        cookie.setMaxAge(60*60*24*3);
        //将cookie设置到rememberme管理器中
        cookieRememberMeManager.setCookie(cookie);
        //设置cookie的值的加密密钥（设置用户数据序列化以后采用的加密密钥）
        cookieRememberMeManager.setCipherKey(Base64.decode("6ZmI6I2j5Y+R5aSn5ZOlAA=="));
        return cookieRememberMeManager;
    }
}
